package org.pathlet.mybatis;

import org.apache.ibatis.session.SqlSessionFactory;
import org.pathlet.core.*;
import org.pathlet.core.exception.ResourceAccessException;
import org.pathlet.core.exception.ResourceException;
import org.pathlet.core.exception.ResourceNotFoundException;
import org.pathlet.core.BeanPathConverter;

/**
 * Mybatis Mapper资源工厂类
 */
public class MapperResourceFactory implements PathResourceFactory<PathletResource> {

	private PathletContainer container;

	private PathPattern pathPattern = MATCH_PATTERN_ALL;

	private PathPattern typePattern = TYPE_MATCH_PATTERN_ALL;

	private String defaultScope;

	// The start path will append before parse path. For instance: <br/>
	// If this argument is "/service", the all resource path which build from this factory will look like "/service/somepath".
	private Path basePath;

	//The base java package to find bean class. This factory will find the classes under the descendants of this package.
	private String basePackage;

	// A customize class to convert from resourcePath to javaBean Define
	private BeanPathConverter pathConverter;

	protected SqlSessionFactory sqlSessionFactory;

	public PathletContainer getContainer() {
		return this.container;
	}

	public void setContainer(PathletContainer container) {
		this.container = container;
	}

	public void setPathPattern(PathPattern pathPattern) {
		this.pathPattern = pathPattern;
	}

	public PathPattern getTypePattern() {
		return typePattern;
	}

	public void setTypePattern(PathPattern typePattern) {
		this.typePattern = typePattern;
		this.typePattern.setPathSeparator(".");
	}

	public PathPattern getPathPattern() {
		return this.pathPattern;
	}

	public String getDefaultScope() {
		return defaultScope;
	}

	public void setDefaultScope(String defaultScope) {
		this.defaultScope = defaultScope;
	}

	public void setBasePath(Path basePath) {
		this.basePath = basePath;
	}

	public void setBasePackage(String basePackage) {
		this.basePackage = basePackage;
	}

	public void setPathConverter(BeanPathConverter pathConverter) {
		this.pathConverter = pathConverter;
	}

	public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
		this.sqlSessionFactory = sqlSessionFactory;
	}

	public PathletResource createResource(Path resourcePath) throws ResourceException {
		//Created the new BeanResource by resourcePath
		try {
			String className = pathConverter.convertToType(resourcePath, basePath, basePackage);

			Class mapperClazz = getContainer().getPathClassLoader().loadClass(resourcePath, className);
			if(mapperClazz == null) {
				throw new ResourceNotFoundException(resourcePath);
			}
			else if(mapperClazz.isInterface() == false) {
				throw new ResourceAccessException("The class must be interface, but it is " + mapperClazz.getName(), resourcePath);
			}

			return new MapperResource(this, getDefaultScope(), resourcePath, mapperClazz);
		}
		catch(Exception e) {
			throw new ResourceAccessException("Failed to get resource path=" + resourcePath, e, resourcePath);
		}
	}

	@Override
	public Path getPathByType(String type) {
		return pathConverter.converToPath(type, basePath, basePackage);
	}

}
